

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <netio/netio.h>
#include <tmc/alloc.h>
#include <tmc/cpus.h>
#include <tmc/sync.h>
#include <tmc/task.h>

#include "mch.h"
#include "lwip/inet.h"
#include "lwip/tcp.h"
#include "lwip/ip_frag.h"
#include "lwip/netif.h"
#include "lwip/init.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "lwip/timers.h"
#include "tile_if.h"


extern int server_init(struct ip_addr *ipaddr, u16_t port);

static struct timeval starttime;

u32_t sys_now(void)
{
    struct timeval tv;
    u32_t sec, usec, msec;
    gettimeofday(&tv, NULL);

    sec = (u32_t)(tv.tv_sec - starttime.tv_sec);
    if(tv.tv_usec >= starttime.tv_usec)
        usec = (u32_t)(tv.tv_usec - starttime.tv_usec);
    else{
        sec--;
        usec = (u32_t)(tv.tv_usec+1000000 - starttime.tv_usec);
    }
    msec = sec * 1000 + usec / 1000;
    return msec;
}


int binding_cpu()
{
    cpu_set_t cpus;

    if (tmc_cpus_get_my_affinity(&cpus) != 0)
    {
        printf("Failure in 'tmc_cpus_get_my_affinity()'.");
        return -1;
    }

    if (tmc_cpus_count(&cpus) < 1)
    {
        printf("Insufficient cpus available.");
        return -1;
    }

    if (tmc_cpus_set_my_cpu(tmc_cpus_find_nth_cpu(&cpus, 0)) < 0)
    {
        printf("Failure in 'tmc_cpus_set_my_cpu()'.");
        return -1;
    }

    return 0;

}

int main(void)
{
    ip_addr_t ipaddr, netmask, gw;
    struct netif netif;

    if (binding_cpu() < 0)
    {
        tmc_task_die("Failed to allocate memory for barrier.");
    }

    IP4_ADDR(&gw, 10, 0, 0, 1);
    IP4_ADDR(&ipaddr, 10, 0, 0, 200);
    IP4_ADDR(&netmask, 255, 255, 255, 0);
    gettimeofday(&starttime, NULL);

    mch_printf("TCP server start...\n");

    lwip_init();

    strncpy(netif.netio_ifname, "gbe/1", 8);
    netif.worker_id = 0;
    netif_add(&netif, &ipaddr, &netmask, &gw, NULL, tile_if_init, ethernet_input);
    /* wait barrier here, and then start netio. */
    if (netif.worker_id == 0) {
        tile_if_start(&netif, 1);
    }
    netif_set_default(&netif);
    netif_set_up(&netif);

    server_init(IP_ADDR_ANY, 80);

    while (1)
    {
        tile_if_input(&netif);
        sys_check_timeouts();

    }
}